using System;
using System.Workflow.ComponentModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Workflow.Activities;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Workflow.ComponentModel.Design;
using System.Drawing.Design;
using System.Runtime.Serialization;
using OpenComposite.Workflow.Properties;

namespace OpenComposite.Workflow
{
	//public sealed class ConstantCondition : ActivityCondition
	//{
	//    public static readonly DependencyProperty BooleanValueProperty = DependencyProperty.Register("BooleanValue", typeof(bool), typeof(ConstantCondition), new PropertyMetadata(DependencyPropertyOptions.Metadata));
	//    public bool BooleanValue
	//    {
	//        get { return (bool)GetValue(BooleanValueProperty); }
	//        set { SetValue(BooleanValueProperty, value); }
	//    }
	//    public override bool Evaluate(Activity activity, IServiceProvider provider)
	//    {
	//        return this.BooleanValue;
	//    }
	//}

	//public sealed class ConstantLoopCondition : ActivityCondition
	//{
	//    private int counter = 0;
	//    public static readonly DependencyProperty MaxCountProperty = DependencyProperty.Register("MaxCount", typeof(int), typeof(ConstantLoopCondition), new PropertyMetadata(DependencyPropertyOptions.Metadata));
	//    public int MaxCount
	//    {
	//        get { return (int)GetValue(MaxCountProperty); }
	//        set { SetValue(MaxCountProperty, value); }
	//    }

	//    public override bool Evaluate(Activity activity, IServiceProvider provider)
	//    {
	//        return counter++ < this.MaxCount;
	//    }
	//}

	[Designer(typeof(WhileDesigner), typeof(IDesigner))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.whileloop.PNG")]
	[ToolboxItem(typeof(HorizontalWhileActivityToolboxItem))]
	public class HorizontalWhileActivity : SequenceActivity
	{
		public static readonly DependencyProperty MaxLoopsProperty = DependencyProperty.Register("MaxLoops", typeof(int), typeof(HorizontalWhileActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
		public int MaxLoops
		{
			get { return (int)GetValue(MaxLoopsProperty); }
			set { SetValue(MaxLoopsProperty, value); }
		}

		public static readonly DependencyProperty TestTimeProperty = DependencyProperty.Register("TestTime", typeof(CheckTime), typeof(HorizontalWhileActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
		public CheckTime TestTime
		{
			get { return (CheckTime)GetValue(TestTimeProperty); }
			set { SetValue(TestTimeProperty, value); }
		}

		public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register("Condition", typeof(ActivityCondition), typeof(HorizontalWhileActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
		public ActivityCondition Condition
		{
			get
			{
				return GetValue(ConditionProperty) as ActivityCondition;
			}

			set { SetValue(ConditionProperty, value); }
		}

		private int _currentLoops = 0;

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
		{
			if ( TestTime == CheckTime.Before ) {
				if ( Condition != null && Condition.Evaluate(this, context) && MaxLoops > _currentLoops ) {
					ExecuteBody(context);
					return ActivityExecutionStatus.Executing;
				}
			} else {
				ExecuteBody(context);
				return ActivityExecutionStatus.Executing;
			}

			return ActivityExecutionStatus.Closed;
		}

		void ExecuteBody(ActivityExecutionContext context)
		{
			ActivityExecutionContextManager manager = context.ExecutionContextManager;
			ActivityExecutionContext newContext;
			Activity newActivity;

			if ( TestTime == CheckTime.After ) {
				newContext = manager.CreateExecutionContext(EnabledActivities[0]);
				newActivity = newContext.Activity;

				newActivity.Closed += this.ContinueAt;
				newContext.ExecuteActivity(newActivity);
			} else {
				if ( Condition != null && Condition.Evaluate(this, context) && MaxLoops > _currentLoops ) {
					newContext = manager.CreateExecutionContext(EnabledActivities[0]);
					newActivity = newContext.Activity;

					newActivity.Closed += this.ContinueAt;
					newContext.ExecuteActivity(newActivity);
				} else { /*if (newActivity.ExecutionStatus == ActivityExecutionStatus.Executing)*/
					context.CloseActivity();
				}
				//	else { }
			}
		}

		void ContinueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= this.ContinueAt;
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			ActivityExecutionContextManager manager = context.ExecutionContextManager;
			ActivityExecutionContext innerContext = manager.GetExecutionContext(e.Activity);
			manager.CompleteExecutionContext(innerContext);

			if ( TestTime == CheckTime.After ) {
				if ( this.ExecutionStatus == ActivityExecutionStatus.Executing &&
					Condition != null && Condition.Evaluate(this, context) && MaxLoops > _currentLoops )
					ExecuteBody(context);
				else
					context.CloseActivity();
			} else {
				ExecuteBody(context);
			}
		}
	}

	public class WhileDesigner : HorizontalSequenceDesigner
	{
		//private Pen _border = new Pen(Brushes.Black, 1.5F);
		private int _loopSize = 10;
		private readonly Size _minimumSize = new Size(200, 70);
		private Rectangle _ExpandButtonRectangle = new Rectangle(0, 0, 8, 8);

		protected override void OnPaint(ActivityDesignerPaintEventArgs e)
		{
			if ( !IsVisible )
				return;


			e.Graphics.DrawRectangle(e.DesignerTheme.BorderPen, Bounds);

			if ( Expanded ) {
				base.OnPaint(e);

			} else {
				e.Graphics.DrawString(Activity.QualifiedName, e.DesignerTheme.Font,
					e.DesignerTheme.ForegroundBrush,
					Bounds.Left + 20.0F,
					WorkflowHelpers.GetCenter(Bounds).Y - e.Graphics.MeasureString(Activity.QualifiedName, e.DesignerTheme.Font).Height / 2);
			}

			ActivityDesignerPaint.DrawExpandButton(e.Graphics, ExpandButtonRectangle, Expanded, (CompositeDesignerTheme)e.DesignerTheme);

			e.Graphics.DrawArc(e.DesignerTheme.ForegroundPen, new Rectangle(
				new Point(Location.X + ( Size.Width / 2 ) - ( _loopSize / 2 ), Bounds.Bottom - ( _loopSize + 3 )),
				new Size(_loopSize, _loopSize)), 130, 270);

			e.Graphics.FillPolygon(Brushes.Black,
				new Point[]{
					new Point(Bounds.X+Bounds.Width/2-_loopSize/2-1,Bounds.Bottom-4),
		            new Point(Bounds.X+Bounds.Width/2-_loopSize/2+3,Bounds.Bottom-7),
		            new Point(Bounds.X+Bounds.Width/2-_loopSize/2+4,Bounds.Bottom-2)
				}, FillMode.Winding);
		}

		protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
		{
			if ( !Expanded )
				return MinimumSize;
			else {
				Size size = base.OnLayoutSize(e);
				size.Height += 20;
				size.Width -= 80;
				return size;
			}
		}

		protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
		{
			base.OnLayoutPosition(e);

			if ( this.Activity.QualifiedName != this.Activity.GetType().Name ) {
				if ( ContainedDesigners.Count == 0 ) {
					List<Activity> list = new List<Activity>();
					list.Add(new WhileSequence());
					ReadOnlyCollection<Activity> roc = new ReadOnlyCollection<Activity>(list);
					InsertActivities(HitTest(Location), roc);
				}

				ContainedDesigners[0].Location =
					new Point(ContainedDesigners[0].Location.X - 40,
						ContainedDesigners[0].Location.Y);
			}
		}

		public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
		{
			return false;
		}

		public override Size MinimumSize
		{
			get
			{
				return _minimumSize;
			}
		}

		public override void RemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
		{
			List<Activity> list = new List<Activity>();
			list.Add(ContainedDesigners[0].Activity);
			ReadOnlyCollection<Activity> roc = new ReadOnlyCollection<Activity>(list);
			ParentDesigner.RemoveActivities(roc);
		}

		protected override Rectangle ExpandButtonRectangle
		{
			get
			{
				if ( Expanded )
					_ExpandButtonRectangle.Location =
						new Point(Bounds.Left + 6,
							Bounds.Top + 6);
				else
					_ExpandButtonRectangle.Location =
						new Point(Bounds.Left + 7,
							WorkflowHelpers.GetCenter(Bounds).Y - _ExpandButtonRectangle.Height / 2);
				return _ExpandButtonRectangle;
			}
		}

		protected override LineAnchor AlternateEndLineAnchor
		{
			get { return LineAnchor.None; }
		}

		protected override LineAnchor EndLineAnchor
		{
			get
			{
				return LineAnchor.None;
			}
		}
	}

	[Designer(typeof(WhileSequenceDesigner), typeof(IDesigner))]
	public class WhileSequence : HorizontalSequenceActivity
	{ }

	public class WhileSequenceDesigner : HorizontalSequenceDesigner
	{
		public override bool CanBeParentedTo(CompositeActivityDesigner parentActivityDesigner)
		{
			return ( parentActivityDesigner is WhileDesigner );
		}
	}

	public class HorizontalWhileActivityToolboxItem : ActivityToolboxItem
	{
		public HorizontalWhileActivityToolboxItem(Type type)
			: base(type)
		{
			this.DisplayName = "Loop";
		}

		private HorizontalWhileActivityToolboxItem(SerializationInfo info, StreamingContext context)
		{
			Deserialize(info, context);
		}
	}

	public enum CheckTime
	{
		Before = 0,
		After = 1
	}
}
